

#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Log.hpp"
#include "Daemon.hpp"
#include <memory>
#include <signal.h>

static void Usage(const std::string &process)
{
    std::cout << "\nUsage: " << process << " port\n"
              << std::endl;
}

ns_protocol::Response calculatorHelper(const ns_protocol::Request &req)
{
    // 根据op选项进行计算
    ns_protocol::Response resp(0, 0);
    switch (req.op_)
    {
    case '+':
        resp.result_ = req.x_ + req.y_;
        break;
    case '-':
        resp.result_ = req.x_ - req.y_;
        break;
    case '*':
        resp.result_ = req.x_ * req.y_;
        break;
    case '/':
        if (req.y_ == 0) // 除零错误，需要设置状态码
            resp.code_ = 1;
        else
            resp.result_ = req.x_ / req.y_;
        break;
    case '%':
        if (req.y_ == 0) // 模零错误，需要设置状态码
            resp.code_ = 2;
        else
            resp.result_ = req.x_ % req.y_;
        break;
    default: // 输入错误，需要设置状态码
        resp.code_ = -1;
        break;
    }
    return resp; // 返回结果（响应：结构体对象）
}

void calculator(int sock) // 服务端用于提供业务的函数
{
    std::string buffer;//临时缓冲区：用于存储recv读取上来的请求
    while (true)
    {
        // Recv读取请求（客户端经过网络传输发来的数据，属于字节流数据，即客户端在发送前会做序列化处理）
        bool ret = ns_protocol::Recv(sock, buffer);
        if(!ret) //读取失败：直接结束
            break;

        // 解析协议，判断读取到的是否是完整的报文。
        std::string package = ns_protocol::Decode(buffer);
        if(package.empty())//报文不完整
            continue;//继续重新读取，直到读取到完整的报文
        logMessage(NORMAL,"本次请求: %s",package.c_str());

        // 当读取到完整的报文后，将请求反序列化（字节流→结构化，服务端要进行上层业务处理，使用的是结构化的数据，所以要进行反序列化）
        ns_protocol::Request req;
        req.Deserialized(package);

        // 进行业务处理，获取结构化存储的结果（结构化数据）
        ns_protocol::Response resp = calculatorHelper(req);
       
        // 将结果序列化（结构化→字节流，服务端要将处理后的结果通过网络传输返回给客户端，需要进行序列化处理）
        std::string result_string = resp.Serialize();
       
        // 对序列化后的结果添加长度信息，形成完整的报文
        result_string = ns_protocol::Encode(result_string);
        logMessage(NORMAL,"本次响应: %s",result_string.c_str());
       
        // 返回客户端响应
        ns_protocol::Send(sock, result_string);
    }
}


////测试：对写端关闭，读端退出的问题说明
// void handler(int signum)
// {
//     std::cout << "捕获：" << signum <<std::endl;
// }

// 启动：./CalServer port
int main(int argc, char *argv[])
{
    // 检查命令行参数,获取命令行端口号
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }
    //signal(SIGPIPE,SIG_IGN);//此句在自定义daemon中写过

    //让进程守护进程化
    MyDaemon();

    // 创建服务器
    std::unique_ptr<ns_tcpserver::TcpServer> server(new ns_tcpserver::TcpServer(atoi(argv[1])));
    // 绑定业务处理函数：这里是网络计算器
    server->BindService(calculator);
    // 启动服务器
    server->Start();

    // //测试：用于测试序列化、反序列化·自定义写法是否正确
    // //  1.1、测试序列化
    // ns_protocol::Request req(1234, 5678, '+');
    // std::string str = req.Serialize();
    // std::cout << "Request-Serialize: " << str << std::endl;
    // std::cout<< std::endl;

    // // 1.2、测试反序列化
    // ns_protocol::Request req2;
    // req2.Deserialized(str);
    // std::cout << "Request-Deserialize: " << std::endl;
    // std::cout << "x: " << req2.x_ << "  y: " << req2.y_ << "  op: " << req2.op_ << std::endl;
    // std::cout<< std::endl;

    // // 2.1、测试序列化
    // ns_protocol::Response resp(6012,0);
    // std::string str2 = resp.Serialize();
    // std::cout << "Response-Serialize: " << str2 << std::endl;
    // std::cout<< std::endl;

    // // 2.2、测试反序列化
    // ns_protocol::Response resp2;
    // resp2.Deserialized(str2);
    // std::cout << "Response-Deserialize: " << std::endl;
    // std::cout << "code: " << resp2.code_ << "  result: " << resp2.result_ << std::endl;
    // std::cout<< std::endl;

    return 0;
}
